package com.infolab.aims.aspect;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import com.infolab.aims.GlobalConstant;
import com.infolab.aims.common.CommonUtil;
import com.infolab.aims.common.SpecialToStringStyle;
import com.infolab.aims.common.bean.AbstractModelBean;
import com.infolab.aims.domain.Audit;
import com.infolab.aims.domain.SystemUser;
import com.infolab.aims.service.intf.AuditService;

@Aspect
public class AuditAspect {

	private static final Logger logger = Logger.getLogger(AuditAspect.class);

	public static final String[] OPERATIONS = { "create", "update", "delete","login", "approve" ,"close","password"};

	@Autowired
	AuditService auditService;
	
	@Around("execution(* com.infolab.aims.web.security.AuthenticationHandler.onAuthenticationSuccess(..))")
	public Object afterLogin(ProceedingJoinPoint pjp) throws Throwable {
		Object result = null;
		result = pjp.proceed();
		
		Object objs[] = pjp.getArgs();
		HttpServletRequest request =null;
		for (Object obj : objs) {
			if (obj instanceof HttpServletRequest ) {
				request = (HttpServletRequest) obj;
				break;
			}
		}
		if(request!=null)
		{
			SystemUser systemUser = (SystemUser) request.getSession().getAttribute(GlobalConstant.SESSION_CURRENT_SYSTEMUSER);
			if(systemUser!=null)
			{
				Audit audit = new Audit();
				audit.setContentHead(systemUser.getUserName()+" is authenticated");
				audit.setCreatedBy(systemUser.getUserName());
				audit.setDateCreated(new Date());
				audit.setModuleName("Authentication");
				audit.setOperation("login");
				auditService.createAudit(audit);
			}
		}
		
		return result;
	}
	
	

	@Around("execution(* com.infolab.aims.service..*(..)) && !execution(* com.infolab.aims.service..AuditService.*(..))")
	public Object afterReturning(ProceedingJoinPoint pjp) throws Throwable {
		Object result = null;
	
		String operationMethodName = pjp.getSignature().getName();
		String operation = null;
		String createdBy = null;
		Date dateCreated = null;
		String modulename = null;
		String contentHead = null;
		String contentDetail = null;
		String auditCode = null;

		for (String tmp : OPERATIONS) {
			if (StringUtils.contains(operationMethodName, tmp)) {
				operation = tmp;
				break;
			}
		}
		
		if (StringUtils.isEmpty(operation)) {
			operation = "undefined";
		}
		

		modulename = StringUtils.substringAfter(operationMethodName, operation);

		if (StringUtils.isEmpty(modulename)) {
			operation = "undefined";
		}
		
		else if(StringUtils.equals(modulename, "UserPassword")){
			operation = "password";
		}
		
		else if(StringUtils.equals(modulename, "InitialBalance")){
			operation = "create";
		}

		try {
			result = pjp.proceed();
			
			
			if(!StringUtils.equalsIgnoreCase("undefined", operation))
			{
			Object objs[] = pjp.getArgs();
			for (Object obj : objs) {
				if (obj instanceof AbstractModelBean) {
					AbstractModelBean tmp = (AbstractModelBean) obj;
					createdBy = tmp.getCreatedBy();
					if(StringUtils.isEmpty(createdBy))
						createdBy=tmp.getModifiedBy();
					
					dateCreated = new Date();
					if(StringUtils.equals(modulename, "UserRoles")){					
						
						contentHead =  tmp.getAuditContentHeadForUserRole();
						contentDetail = tmp.getAuditContentDetail();
						auditCode = tmp.getAuditCode()+" Roles";
					}					
					
					else if(StringUtils.equals(modulename, "User")){
						contentHead =  tmp.getAuditContentHead();
						contentDetail = null;
						auditCode = tmp.getAuditCode();
						
					}
					
					else{
						contentHead = tmp.getAuditContentHead();
						contentDetail = tmp.getAuditContentDetail();
						auditCode = tmp.getAuditCode();
					}					
					
					
					break;
				}
				
				if(StringUtils.equals(modulename, "UserPassword")){
					//SystemUser systemUser = (SystemUser) request.getSession().getAttribute(GlobalConstant.SESSION_CURRENT_SYSTEMUSER);
					dateCreated = new Date();
					String userName = (String) obj;
					createdBy = userName;
					contentHead =  new ToStringBuilder(this,SpecialToStringStyle.SPECIAL_STYLE)
								   .append(userName +"'s password has been changed").toString();
					contentDetail = "No detailed summary is available";					
					auditCode = userName;
					break;					
				}	
				
								
					
			}
			
			 
			
			
			if (createdBy == null) {
				createdBy = "undefined";
			}

			if (dateCreated == null) {
				dateCreated = new Date();
			}
			
			Audit audit = new Audit();
			if(!operation.equalsIgnoreCase("password"))
				audit.setAuditCode(auditCode);
			
			audit.setContentHead(contentHead);
			
			if(contentDetail != null && contentDetail.length()>2000){
				contentDetail=contentDetail.substring(0,1997)+"..]";
			}
			audit.setContentDetail(contentDetail);
			audit.setCreatedBy(createdBy);
			audit.setDateCreated(dateCreated);
			audit.setModuleName(modulename);
			audit.setOperation(operation);
			auditService.createAudit(audit);
			
			
			}

		} catch (Throwable e) {
			logger.error(CommonUtil.getStackTrace(e));
			if (logger.isInfoEnabled()) {
				logger.error("Exception Caught!"); //$NON-NLS-1$
				logger.error(operationMethodName+" "+pjp.getArgs());
			}
			throw e;
		}
		return result;

	}

}